import random
import time


class Job:
    def __init__(self, id, arrival_time, burst_time):
        self.id = id
        self.arrival_time = arrival_time
        self.burst_time = burst_time
        self.remaining_time = burst_time
        self.start_time = None
        self.finish_time = None
        self.turnaround_time = None
        self.weighted_turnaround_time = None

    def __str__(self):
        return f"作业{self.id}: 到达时间={self.arrival_time}, 运行时间={self.burst_time}"


class JobScheduler:
    def __init__(self, num_jobs=10, time_slice=0.5):
        self.num_jobs = num_jobs
        self.time_slice = time_slice
        self.jobs = []
        self.ready_queue = []
        self.running_queue = []
        self.finished_queue = []
        self.current_time = 0

    def generate_jobs(self):
        '''
        for i in range(self.num_jobs):
            arrival_time = random.randint(0, 10)  # 随机生成整数到达时间
            burst_time = random.randint(1, 5)  # 随机生成整数作业时间
            job = Job(i + 1, arrival_time, burst_time)
            self.jobs.append(job)
            print(job)  # 打印作业信息
        '''
        self.jobs = [Job(0, 0, 1), Job(1, 1, 3), Job(2, 4, 4), Job(3, 3, 9), Job(4, 10, 5)]

    def print_queues(self):
        print(f"当前时间: {self.current_time}")
        print(f"就绪队列: {[job.id for job in self.ready_queue]}")
        print(f"运行队列: {[job.id for job in self.running_queue]}")
        print(f"结束队列: {[job.id for job in self.finished_queue]}")
        print()

    def print_jobs(self):
        print("作业ID\t到达时间\t运行时间\t开始时间\t结束时间\t周转时间\t带权周转时间")
        for job in self.finished_queue:
            print(job.id, "\t", job.arrival_time, "\t", job.burst_time, "\t",
                  job.start_time, "\t", job.finish_time, "\t", job.turnaround_time, "\t", job.weighted_turnaround_time,
                  sep="")

    def fcfs(self):
        print("fcfs:")
        self.generate_jobs()
        self.jobs.sort(key=lambda x: x.arrival_time)
        while self.jobs or self.running_queue or self.ready_queue:
            flag = 0
            for job in self.jobs:
                if job.arrival_time <= self.current_time:
                    self.ready_queue.append(job)
                    self.jobs.remove(job)

            if self.running_queue:
                current_job = self.running_queue[0]
                current_job.remaining_time -= self.time_slice

                if current_job.remaining_time <= 0:
                    current_job.finish_time = self.current_time
                    current_job.turnaround_time = current_job.finish_time - current_job.arrival_time
                    current_job.weighted_turnaround_time = current_job.turnaround_time / current_job.burst_time
                    self.finished_queue.append(current_job)
                    self.running_queue.pop(0)
                    flag = 1
            else:
                if self.ready_queue:
                    self.ready_queue.sort(key=lambda x: x.arrival_time)
                    running_job = self.ready_queue.pop(0)
                    running_job.start_time = self.current_time
                    self.running_queue.append(running_job)

            if flag == 0:
                self.current_time += self.time_slice
                self.print_queues()
                time.sleep(self.time_slice)

        self.print_jobs()
        total_turnaround_time = sum([job.turnaround_time for job in self.finished_queue])
        total_weighted_turnaround_time = sum([job.weighted_turnaround_time for job in self.finished_queue])
        print("平均周转时间: ", total_turnaround_time / len(self.finished_queue))
        print("平均带权周转时间: ", total_weighted_turnaround_time / len(self.finished_queue))

    def sjf(self):
        print("sjf:")
        self.generate_jobs()
        while len(self.jobs) > 0 or len(self.ready_queue) > 0 or len(self.running_queue) > 0:
            # 将到达时间小于等于当前时间的作业加入就绪队列
            for job in self.jobs:
                if job.arrival_time <= self.current_time:
                    self.ready_queue.append(job)
                    self.jobs.remove(job)

            if len(self.running_queue) == 0 and len(self.ready_queue) > 0:
                # 如果运行队列为空且就绪队列不为空，选择最短作业并加入运行队列
                shortest_job = min(self.ready_queue, key=lambda x: x.burst_time)
                self.ready_queue.remove(shortest_job)
                self.running_queue.append(shortest_job)
                shortest_job.start_time = self.current_time

            if len(self.running_queue) > 0:
                # 如果运行队列不为空，减少正在运行的作业的剩余运行时间
                running_job = self.running_queue[0]
                running_job.remaining_time -= self.time_slice
                if running_job.remaining_time <= 0:
                    # 如果剩余时间小于等于0，标记作业为完成
                    running_job.finish_time = self.current_time + self.time_slice
                    running_job.turnaround_time = running_job.finish_time - running_job.arrival_time
                    running_job.weighted_turnaround_time = running_job.turnaround_time / running_job.burst_time
                    self.finished_queue.append(running_job)
                    self.running_queue.remove(running_job)

            self.print_queues()  # 打印队列状态
            time.sleep(self.time_slice)  # 休眠一段时间，模拟时间片
            self.current_time += self.time_slice  # 更新当前时间

        # 计算并打印平均周转时间和平均带权周转时间
        self.print_jobs()
        total_turnaround_time = sum([job.turnaround_time for job in self.finished_queue])
        total_weighted_turnaround_time = sum([job.weighted_turnaround_time for job in self.finished_queue])
        print("平均周转时间: ", total_turnaround_time / len(self.finished_queue))
        print("平均带权周转时间: ", total_weighted_turnaround_time / len(self.finished_queue))


if __name__ == "__main__":
    num_jobs = int(input("输入作业个数 (默认10): ") or "10")
    time_slice = float(input("输入时间片长度（默认0.5秒）: ") or "0.5")

    scheduler = JobScheduler(num_jobs, time_slice)

    # 选择算法
    choice = input("请输入要选择的算法，fcfs或sjf: ")
    if choice == "fcfs":
        scheduler.fcfs()
    elif choice == "sjf":
        scheduler.sjf()
